package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.Constants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.RoleResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private RoleResourceMapper roleResourceMapper;

    @Override
    @Cacheable(cacheNames = "resource:list", key = "#resourceDto.hashCode()")
    public List<ResourceVo> selectList(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        List<ResourceVo> list = resourceMapper.selectList(resource);
        return list;
    }

    @Override
    @Cacheable(cacheNames = "resource:tree", key = "#resourceDto.hashCode()")
    public TreeVo selectToTree(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        String root = NoProcessing.processString(SuperConstant.ROOT_PARENT_ID);
        resource.setParentResourceNo(root);
        resource.setResourceType(SuperConstant.MENU);
        List<ResourceVo> resourceVos = resourceMapper.selectList(resource);

        List<TreeItemVo> list = new ArrayList<>();

        String label = "智慧养老院";
        treeBuilder(list, SuperConstant.ROOT_PARENT_ID, label, resourceVos);

        TreeVo treeVo = new TreeVo();
        treeVo.setItems(list);
        return treeVo;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "resource:tree", allEntries = true),
            @CacheEvict(cacheNames = "resource:list", allEntries = true)
    })
    public void addResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        //判断父级菜单是否为三级，是三级则抛异常
        String string = NoProcessing.processString(resource.getParentResourceNo());
        if (resource.getResourceType().equals(SuperConstant.MENU) && string.length() == 15) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        resource.setResourceNo(getResourceNo(resource));
        resourceMapper.insertResource(resource);
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "resource:tree", allEntries = true),
            @CacheEvict(cacheNames = "resource:list", allEntries = true)
    })
    public void updateResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resourceMapper.updateResource(resource);
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "resource:tree", allEntries = true),
            @CacheEvict(cacheNames = "resource:list", allEntries = true)
    })
    public void updateDataStatus(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        String no = NoProcessing.processString(resource.getResourceNo());
        resource.setResourceNo(no);
        Resource res = resourceMapper.selectByParentNo(resource.getParentResourceNo());
        if (res.getDataState().equals("1")) {
            throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
        }
        resourceMapper.updateStatus(resource);
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "resource:tree", allEntries = true),
            @CacheEvict(cacheNames = "resource:list", allEntries = true)
    })
    public void deleteResource(String resourceNo) {
        //判断是否有子级
        Integer count = resourceMapper.selectChildsByResourceNo(resourceNo);
        //有子集不可删除
        if (count > 0) {
            throw new BaseException(BasicEnum.EXIST_CHILD_MENU_ERROR);
        }
        // 菜单已分配角色，不允许删除
        Integer countNo = roleResourceMapper.selectResourcesByResourceNo(resourceNo);

        if (countNo > 0) {
            throw new BaseException(BasicEnum.MENU_DISTRIBUTED_ERROR);
        }

        resourceMapper.deleteResource(resourceNo);
    }

    @Override
    public List<MenuVo> getMenu() {
        //获取当前用户id
        Long userId = UserThreadLocal.getUserId();

        //查询所有menu
        List<MenuVo> menuVos = resourceMapper.selectMenuVoByUserId(userId);

        //根据parentId分组
        Map<String, List<MenuVo>> parentMap = menuVos.stream().collect(Collectors.groupingBy(MenuVo::getParentResourceNo));

        menuVos.forEach(menuVo -> {
            MenuMetaVo menuMetaVo = new MenuMetaVo();
            menuMetaVo.setTitle(menuVo.getName());
            menuVo.setMeta(menuMetaVo);
            if(menuVo.getRedirect()==null||menuVo.getRedirect().length()==0){
                menuVo.setRedirect("/" + menuVo.getName());
            }

            List<MenuVo> childs = parentMap.get(menuVo.getResourceNo());

            if (childs != null && childs.size() != 0) {
                childs.forEach(menuVo1 -> {
                    MenuMetaVo menuMeta= new MenuMetaVo();
                    menuMeta.setTitle(menuVo1.getName());
                    menuVo1.setMeta(menuMeta);
                    menuVo1.setRedirect(menuVo.getRedirect()+"/"+menuVo1.getName());
                });
            }
            menuVo.setChildren(childs);

        });


        return parentMap.get(SuperConstant.ROOT_PARENT_ID);
    }


    private void treeBuilder(List<TreeItemVo> list, String root, String lable, List<ResourceVo> resourceVos) {
        TreeItemVo treeItemVo = new TreeItemVo();
        treeItemVo.setId(root);
        treeItemVo.setLabel(lable);

        List<ResourceVo> childs = resourceVos.stream().filter(obj -> obj.getParentResourceNo().equals(treeItemVo.getId())).collect(Collectors.toList());
        if (childs != null && childs.size() != 0) {
            List<TreeItemVo> list1 = new ArrayList<>();
            childs.forEach(child -> {
                treeBuilder(list1, child.getResourceNo(), child.getResourceName(), resourceVos);
            });
            treeItemVo.setChildren(list1);
        }
        list.add(treeItemVo);
    }

    private String getResourceNo(Resource resource) {
        String parentResourceNo = NoProcessing.processString(resource.getParentResourceNo());
        Resource resource1 = new Resource();
        resource1.setParentResourceNo(parentResourceNo);
        resource1.setResourceType(SuperConstant.MENU);
        List<ResourceVo> resourceVos = resourceMapper.selectList(resource1);
        String no;
        if (resourceVos != null && resourceVos.size() != 0) {
            long max = resourceVos.stream().mapToLong(vo -> Long.valueOf(vo.getResourceNo())).max().getAsLong();
            no = NoProcessing.createNo(Long.toString(max), true);
            return no;
        }
        no = NoProcessing.createNo(resource.getResourceNo(), false);
        return no;
    }
}
